/*
    Speedbump aka Project Kimbula
    Copyright (C) 2010  Ping Shin Ching

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses.

	Ping Shin Ching
	righteous.ninja@gmail.com OR ping_sc@hotmail.com
	More information at http://www.tidytutorials.com/p/speedbump.html
 */


#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <semaphore.h>
#include <sys/time.h>
#include <time.h>

#include "logger.h"

Logger proxylog;
/*************************************************************************
 * Setup the logger including the /dev/null streams
 *************************************************************************/
int Logger::Setuplogger(short int loglevel, const char* filename){
	
	devnull = new std::ofstream();
	devnull->rdbuf(new DevNull());

	globalloglevel = (2<<(loglevel-1))-1;

	if( strcmp(filename, "stdout")){
		plogofs = new std::ofstream(filename);
		return 1;
	}
	else{
		plogofs =  &std::cout;
		return 1;
	}
}


/*************************************************************************
 * Close the logger
 *************************************************************************/
void Logger::Closelogger(){
	std::ofstream* pofs;

	if((pofs=dynamic_cast<std::ofstream*>(plogofs))){
		pofs->close();
		delete plogofs;
	}
	if((pofs=dynamic_cast<std::ofstream*>(devnull))){
		pofs->close();
	}

	delete devnull;

	CloseAccesslogger();
}


/*************************************************************************
 * Flush the logger
 *************************************************************************/
void Logger::Flushlogger(){
	plogofs->flush();
}


/*************************************************************************
 * Get the logstream
 *************************************************************************/
std::ofstream* Logger::Getlogger(LOGLEVEL loglevel){
	if( (loglevel | globalloglevel) == globalloglevel){
		struct timeval tv;
		char tmptime[32]={'\0'};

		time((time_t*)&tv);
		strncpy(tmptime, ctime((time_t*)&tv), 24);

#ifdef THREADXX
		*plogofs<<tmptime<<std::dec<<" ["<<pthread_self()<<"] "<<std::dec;
#else
		*plogofs<<tmptime<<std::dec<<" ["<<getpid()<<"] "<<std::dec;
#endif

		switch(loglevel){
		case LOG_CRITICAL:
			*plogofs<<"CRITICAL: ";
			break;
		case LOG_ERROR:
			*plogofs<<"ERROR: ";
			break;
		case LOG_WARN:
			*plogofs<<"WARN: ";
			break;
		case LOG_INFO:
			*plogofs<<"INFO: ";
			break;
		case LOG_DEBUG:
			*plogofs<<"DEBUG: ";
			break;
		default:
			*plogofs<<"UNKNOWN: ";
			break;
		}
		
		return (std::ofstream*)plogofs; 	
	}
	else
		return (std::ofstream*)devnull;
}


/*************************************************************************
 * Return a null logger for when you don't want to log
 *************************************************************************/
std::ofstream* Logger::GetNullLogger(){
	return (std::ofstream*)devnull;
}


/*************************************************************************
 * Print the logging details to stdout
 *************************************************************************/
void Logger::Printlogdetails(){
	switch(globalloglevel){
	case LOG_CRITICAL:
		printf("Logging is set to CRITICAL\n");
		break;
	case LOG_ERROR:
		printf("Logging is set to ERROR\n");
		break;
	case LOG_WARN:
		printf("Logging is set to WARN\n");
		break;
	case LOG_INFO:
		printf("Logging is set to INFO\n");
		break;
	case LOG_DEBUG:
		printf("Logging is set to DEBUG\n");
		break;
	default:
		printf("Logging is set to UNKNOWN\n");
		break;
	}
}

int Logger::SetupAccesslogger(const char* filename){
	sem_unlink("/ninja2");
	if((access_sem = sem_open("/ninja2", O_CREAT, "0644", 1))==SEM_FAILED){
		printf("---%d\n", errno);
		assert(0);
		return -1;
	}
	accessofs = new std::ofstream(filename);
	access_fp=fopen("access.log", "w");
	return 0;
}

void Logger::ALog(const char* format, ...){
	va_list ap;
	va_start(ap, format);
	vfprintf(access_fp, format, ap);
	va_end(ap);
	fflush(access_fp); // only for debug 
}

std::ofstream* Logger::GetAccesslogger(){
	struct timespec ts;

	ts.tv_sec=1;
	ts.tv_nsec=0;
	/*
	if(sem_timedwait(access_sem, &ts)==-1){
		if(errno==ETIMEDOUT){
			printf("SEM wait failed timeout\n");
		}
		else{
			printf("SEM wait failed -other\n");

		}

	}else{
		printf("SEM wait success\n");
	}
	if(sem_post(access_sem)==-1){
		printf("SEM Post failed %d\n", errno);
	}
	*/
	return dynamic_cast<std::ofstream*>(&std::cout);
	//return (std::ofstream*)accessofs;
}

void Logger::CloseAccesslogger(){
	printf("closing sem\n");
	sem_close(access_sem);
	if(access_fp){
		fclose(access_fp);
		access_fp=0;
	}
}
